home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-06 / ipxstuff.zip / RKIPX.C < prev    next >
C/C++ Source or Header  |  1993-03-09  |  43KB  |  1,500 lines

  1.  
  2. /***************************************************/
  3. /***************************************************/
  4. /* IPX LIBRARY ROUTINES                            */
  5. /* (c) 1992 by R. Kvinnesland                      */
  6. /***************************************************/
  7. /***************************************************/
  8.  
  9. /* ------- */
  10. /* ------- */
  11. /* headers */
  12. /* ------- */
  13. /* ------- */
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <ctype.h>
  18. #include <dos.h>
  19. #include <time.h>
  20. #include <string.h>
  21. #include <conio.h>
  22. #include <io.h>
  23. #include <fcntl.h>
  24. #include <sys\stat.h>
  25.  
  26. #include "rkipx.h"
  27.  
  28. /* ------------------------------------- */
  29. /* ------------------------------------- */
  30. /* global variables                      */
  31. /* ------------------------------------- */
  32. /* ------------------------------------- */
  33.  
  34. unsigned  IPXerrno;                   // latest IPX error
  35. time_t    IPXto = IPX_TIMEOUT;        // secs to wait for IPX command
  36. unsigned  IPXtries = IPX_TRIES;       // # times to retry RX/TX
  37. unsigned  IPXdatalen = MINIPXDATALEN; // size of IPX packet data buffer
  38.  
  39. /* -------------------------------- */
  40. /* ---- I N T E R N A L  U S E ---- */
  41. /* -------------------------------- */
  42.  
  43. static void (*IPXAPI)(void);
  44.  
  45. /************************************************************************/
  46. /************************************************************************/
  47. /* IPX LOW-LEVEL FUNCTIONS */
  48. /************************************************************************/
  49. /************************************************************************/
  50.  
  51. unsigned IPXInstalled( void )
  52. {
  53. union REGS      regs;
  54. struct SREGS    sregs;
  55.  
  56. regs.x.ax = IPX_MULTIPLEX;
  57. int86x( DOS_MULTIPLEX_VECTOR, ®s, ®s, &sregs );
  58. IPXAPI = MK_FP( sregs.es, regs.x.di );
  59. return( regs.h.al );
  60. }
  61.  
  62. /************************************************************************/
  63. /************************************************************************/
  64.  
  65. unsigned IPXSocketOpen( BYTE *socket, BYTE longevity )
  66. {
  67. _DL = socket[0];
  68. _DH = socket[1];
  69. _AL = longevity;
  70. _BX = SOCKET_OPEN;
  71. IPXAPI();
  72. socket[0] = _DL;
  73. socket[1] = _DH;
  74. _AH = 0;
  75. return( _AX );
  76. }
  77.  
  78. /**************************************************************************/
  79. /**************************************************************************/
  80.  
  81. void IPXSocketClose( BYTE *socket )
  82. {
  83. _DL = socket[0];
  84. _DH = socket[1];
  85. _BX = SOCKET_CLOSE;
  86. IPXAPI();
  87. return;
  88. }
  89.  
  90. /**************************************************************************/
  91. /**************************************************************************/
  92.  
  93. unsigned IPXGetLocalTarget( LOCALTARGET *lt )
  94. {
  95. _ES = FP_SEG( (void far *)lt );
  96. _SI = FP_OFF( (void far *)lt->INA.Network );
  97. _DI = FP_OFF( (void far *)lt->ImmediateAddr );
  98. _BX = GET_LOCAL_TARGET;
  99. IPXAPI();
  100. _AH = 0;
  101.  
  102. return( _AX );
  103. }
  104.  
  105. /**************************************************************************/
  106. /**************************************************************************/
  107.  
  108. void IPXSendPacket( EVENTCONTROLBLOCK *ecb )
  109. {
  110.  
  111. _ES = FP_SEG( (void far *)ecb );
  112. _SI = FP_OFF( (void far *)ecb );
  113. _BX = SEND_PACKET;
  114. IPXAPI();
  115. return;
  116. }
  117.  
  118. /**************************************************************************/
  119. /**************************************************************************/
  120.  
  121. void IPXListenForPacket( EVENTCONTROLBLOCK *ecb )
  122. {
  123.  
  124. _ES = FP_SEG( (void far *)ecb );
  125. _SI = FP_OFF( (void far *)ecb );
  126. _BX = LISTEN_FOR_PACKET;
  127. IPXAPI();
  128. return;
  129. }
  130.  
  131. /**************************************************************************/
  132. /**************************************************************************/
  133.  
  134. void IPXGetInternetworkAddress( INTNETADDR *ina )
  135. {
  136. _ES = FP_SEG( (void far *)ina );
  137. _SI = FP_OFF( (void far *)ina );
  138. _BX = GET_INTERNETWORK_ADDR;
  139. IPXAPI();
  140. return;
  141. }
  142.  
  143. /**************************************************************************/
  144. /**************************************************************************/
  145.  
  146. void IPXRelinquishControl( void )
  147. {
  148. _BX = RELINQUISH_CONTROL;
  149. IPXAPI();
  150. return;
  151. }
  152.  
  153. /**************************************************************************/
  154. /**************************************************************************/
  155.  
  156. void IPXDisconnectFromTarget( NETADDR *naddr )
  157. {
  158. _ES = FP_SEG( (void far *)naddr );
  159. _SI = FP_OFF( (void far *)naddr );
  160. _BX = DISCONNECT_FROM_TARGET;
  161. IPXAPI();
  162. return;
  163. }
  164.  
  165. /**************************************************************************/
  166. /**************************************************************************/
  167.  
  168. unsigned IPXCancelEvent( EVENTCONTROLBLOCK *ecb )
  169. {
  170. _ES = FP_SEG( (void far *)ecb );
  171. _SI = FP_OFF( (void far *)ecb );
  172. _BX = CANCEL_EVENT;
  173. IPXAPI();
  174. _AH = 0;
  175. return( _AX );
  176. }
  177.  
  178. /**************************************************************************/
  179. /**************************************************************************/
  180.  
  181. unsigned IPXGetIntervalMarker( void )
  182. {
  183. _BX = GET_INTERVAL_MARKER;
  184. IPXAPI();
  185. return( _AX );
  186. }
  187.  
  188. /**************************************************************************/
  189. /**************************************************************************/
  190.  
  191. void IPXScheduleEvent( EVENTCONTROLBLOCK *ecb, unsigned delay )
  192. {
  193.  
  194. _ES = FP_SEG( (void far *)ecb );
  195. _SI = FP_OFF( (void far *)ecb );
  196. _AX = delay;
  197. _BX = SCHEDULE_EVENT;
  198. IPXAPI();
  199. return;
  200. }
  201.  
  202. /**************************************************************************/
  203. /**************************************************************************/
  204. /* INTERNAL UTILITY FUNCTIONS */
  205. /**************************************************************************/
  206. /**************************************************************************/
  207.  
  208. int IPXTimeOutRT( EVENTCONTROLBLOCK *ecb,
  209.                   time_t delay,
  210.                   void (*RTfunc)(void) )
  211. {
  212. time_t start_time;
  213.  
  214. start_time = time( NULL );
  215. while ( ecb->InUse )
  216.   {
  217.   IPXRelinquishControl();
  218.   if ( RTfunc != NULL )
  219.      {
  220.      RTfunc();
  221.      }
  222.   if ( (time( NULL ) - start_time) > delay )  // next FULL second!
  223.      {
  224.      IPXCancelEvent( ecb );
  225.      return( TRUE );
  226.      }
  227.   }
  228. return( !TRUE );
  229. }
  230.  
  231. /*************************/
  232. /*************************/
  233.  
  234. /* returns TRUE if characters in string are legal hex digits */
  235.  
  236. int xatoxb( BYTE *d, char *s )
  237. {
  238. while( *s )
  239.   {
  240.   if ( !isxdigit( *s ) )
  241.      {
  242.      return( !TRUE );
  243.      }
  244.   *d = (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7') << 4;
  245.   if ( !isxdigit( *s ) )
  246.      {
  247.      return( !TRUE );
  248.      }
  249.   *d++ += (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7');
  250.   }
  251. return( TRUE );
  252. }
  253.  
  254. /* ======================================================= */
  255.  
  256. /* allows/ignores non-hex ASCII delimiters in string */
  257.  
  258. void xantoxb( BYTE *d, char *s, unsigned len )
  259. {
  260. while( len-- )
  261.   {
  262.   while( !isxdigit( *s ) )
  263.     s++;
  264.   *d = (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7') << 4;
  265.   while( !isxdigit( *s ) )
  266.     s++;
  267.   *d++ += (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7');
  268.   }
  269. return;
  270. }
  271.  
  272. /*************************************************************************/
  273. /*************************************************************************/
  274.  
  275. void ShowECB( EVENTCONTROLBLOCK *ecb )
  276. {
  277. unsigned i;
  278.  
  279. printf( "\n" );
  280. printf( "LINK ADDR: %04X:%04X\n",
  281.         (unsigned)((long)ecb->LinkAddr / SEGSIZE ),
  282.         (unsigned)((long)ecb->LinkAddr % SEGSIZE) );
  283.  
  284. printf( "      ESR: %04X:%04X\n",
  285.         (unsigned)((long)ecb->ESR / SEGSIZE),
  286.         (unsigned)((long)ecb->ESR % SEGSIZE) );
  287.  
  288. printf( "   IN USE: %02X\n",
  289.         ecb->InUse );
  290.  
  291. printf( "COMP CODE: %02X\n",
  292.         ecb->CompletionCode );
  293.  
  294. printf( "   SOCKET: %02X %02X\n",
  295.         ecb->Socket[0],
  296.         ecb->Socket[1] );
  297.  
  298. printf( "IPX WrkSp: %02X %02X %02X %02X\n",
  299.     ecb->IPXWorkspace[0],
  300.         ecb->IPXWorkspace[1],
  301.         ecb->IPXWorkspace[2],
  302.         ecb->IPXWorkspace[3] );
  303.  
  304. printf( "Drv WrkSp: %02X %02X %02X %02X",
  305.         ecb->DriverWorkspace[0],
  306.         ecb->DriverWorkspace[1],
  307.         ecb->DriverWorkspace[2],
  308.         ecb->DriverWorkspace[3] );
  309. printf( " %02X %02X %02X %02X",
  310.         ecb->DriverWorkspace[4],
  311.         ecb->DriverWorkspace[5],
  312.         ecb->DriverWorkspace[6],
  313.         ecb->DriverWorkspace[7] );
  314. printf( " %02X %02X %02X %02X\n",
  315.         ecb->DriverWorkspace[8],
  316.         ecb->DriverWorkspace[9],
  317.         ecb->DriverWorkspace[10],
  318.         ecb->DriverWorkspace[11] );
  319.  
  320. printf( "Immd Addr: %02X %02X %02X %02X %02X %02X\n",
  321.         ecb->ImmediateAddr[0],
  322.         ecb->ImmediateAddr[1],
  323.         ecb->ImmediateAddr[2],
  324.         ecb->ImmediateAddr[3],
  325.         ecb->ImmediateAddr[4],
  326.         ecb->ImmediateAddr[5] );
  327.  
  328. printf( " FRAG CNT: %u\n", ecb->FragmentCnt );
  329.  
  330. for( i = 0; i < ecb->FragmentCnt; i++ )
  331.    {
  332.    printf( "   FRAG %03u - @BUFR: %04X:%04X  LEN: %u\n",
  333.            i+1,
  334.            (unsigned)((long)ecb->Fragment[i].BufAddr / SEGSIZE),
  335.            (unsigned)((long)ecb->Fragment[i].BufAddr % SEGSIZE),
  336.            ecb->Fragment[i].Len );
  337.    }
  338.  
  339. return;
  340. }
  341.  
  342. /*************************************************************************/
  343. /*************************************************************************/
  344.  
  345. void ShowIPXPacket( IPXHEADER *ipxhdr )
  346. {
  347. unsigned i;
  348.  
  349. printf( "\n" );
  350. printf( "    Checksum: %04X\n", HILOSWAP( ipxhdr->Chksum ) );
  351. printf( " IPX Pkt Len: %u\n", HILOSWAP( ipxhdr->Len ) );
  352. printf( " RX Data Len: %u\n", HILOSWAP( ipxhdr->Len ) - sizeof(IPXHEADER) );
  353. printf( "TransprtCtrl: %02X\n", ipxhdr->TransportCtrl );
  354. printf( "  PacketType: %02X\n", ipxhdr->PacketType );
  355.  
  356. printf( " DestNetwork: %02X %02X %02X %02X\n",
  357.     ipxhdr->DestAddr.INA.Network[0],
  358.     ipxhdr->DestAddr.INA.Network[1],
  359.     ipxhdr->DestAddr.INA.Network[2],
  360.     ipxhdr->DestAddr.INA.Network[3] );
  361.  
  362. printf( "    DestNode: %02X %02X %02X %02X %02X %02X\n",
  363.     ipxhdr->DestAddr.INA.Node[0],
  364.     ipxhdr->DestAddr.INA.Node[1],
  365.     ipxhdr->DestAddr.INA.Node[2],
  366.     ipxhdr->DestAddr.INA.Node[3],
  367.     ipxhdr->DestAddr.INA.Node[4],
  368.     ipxhdr->DestAddr.INA.Node[5] );
  369.  
  370. printf( "  DestSocket: %02X %02X\n",
  371.     ipxhdr->DestAddr.Socket[0],
  372.     ipxhdr->DestAddr.Socket[1] );
  373.  
  374. printf( " SrceNetwork: %02X %02X %02X %02X\n",
  375.     ipxhdr->SrceAddr.INA.Network[0],
  376.     ipxhdr->SrceAddr.INA.Network[1],
  377.     ipxhdr->SrceAddr.INA.Network[2],
  378.     ipxhdr->SrceAddr.INA.Network[3] );
  379.  
  380. printf( "    SrceNode: %02X %02X %02X %02X %02X %02X\n",
  381.     ipxhdr->SrceAddr.INA.Node[0],
  382.     ipxhdr->SrceAddr.INA.Node[1],
  383.     ipxhdr->SrceAddr.INA.Node[2],
  384.     ipxhdr->SrceAddr.INA.Node[3],
  385.     ipxhdr->SrceAddr.INA.Node[4],
  386.     ipxhdr->SrceAddr.INA.Node[5] );
  387.  
  388. printf( "  SrceSocket: %02X %02X\n",
  389.     ipxhdr->SrceAddr.Socket[0],
  390.     ipxhdr->SrceAddr.Socket[1] );
  391.  
  392. return;
  393. }
  394.  
  395. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  396. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  397. /* HIGH-LEVEL APPLICATION PROGRAMMING IPX INTERFACE FUNCTIONS */
  398. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  399. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  400.  
  401.  
  402. /*******************************************************************/
  403. /*******************************************************************/
  404. /*
  405.   ------------------------
  406.   ------------------------
  407.   FUNCTION: IPXReceiveRT()
  408.   ------------------------
  409.   ------------------------
  410.  
  411.   Receive data into a buffer or file from a non-specified sender.
  412.  
  413.   NOTE:
  414.   The sender must know the internetwork address and socket of the
  415.   machine that is to receive its transmission(s), but the receiver
  416.   merely has to issue a LISTEN & can then receive from any sender.
  417.  
  418.   ----------
  419.   ----------
  420.   PROTOTYPE:
  421.   ----------
  422.   ----------
  423.  
  424.   unsigned IPXReceiveRT( long   *BfrLen,
  425.                          BYTE   *FileOrBfr,
  426.                          char   *SocketStr,
  427.                          void   (*RTfunc)(void) );
  428.  
  429.   ---------
  430.   ---------
  431.   INPUT(S):
  432.   ---------
  433.   ---------
  434.  
  435.   BfrLen = 0 if receiving a file
  436.              OR
  437.        the maximum # of bytes that can be stored in a given buffer
  438.  
  439.   FileOrBfr = (string) name of file (path optional) into which to write
  440.               the data that is received
  441.                 OR
  442.               pointer to given byte buffer into which to store the data
  443.               that is received
  444.  
  445.   SocketStr = 4 character hex-ASCII string of IPX Socket to
  446.               use for receiving. Note that certain NOVELL sockets
  447.               are reserved, and the caller is cautioned to use
  448.               socket numbers "40xx", e.g., "4010", "40A1", etc.
  449.  
  450.   RTfunc    = pointer to a function which is to be called during
  451.               time out loops when IPX command is pending.  Set
  452.               to NULL if you don't need this "real time" capability.
  453.  
  454.   ----------
  455.   ----------
  456.   RETURN(S):
  457.   ----------
  458.   ----------
  459.  
  460.   0x00 - GOOD_IPX_RETURN - all went well.
  461.  
  462.  
  463.   0x10 - BAD_LOCAL_TARGET - the internal IPX call to find the sender's
  464.   local target failed.  Check the global variable IPXerrno for the
  465.   specific reason, e.g.:
  466.  
  467.          0xFA - DEST_NODE_PATH_NOT_FND - the 6-byte node address
  468.                 specified in the received IPX packet parameter SrceAddr
  469.                 could not be found.  Either the packet was corrupted,
  470.                 or the sending machine with that node has died.
  471.  
  472.  
  473.   0x11 - BAD_SOCKET_PARAM - the SocketStr parameter did not consist of
  474.   a string of four hex-ascii digits.
  475.  
  476.  
  477.   0x12 - BAD_SOCKET_OPEN - the attempt to open the socket specified in
  478.   SocketStr parameter failed.  The global variable IPXerrno will contain
  479.   return code received from IPX.  It can be one of the following:
  480.  
  481.          0xFE - SOCKET_TABLE_FULL - each machine gets 20 sockets, so
  482.                 this error should never occur unless other non-"well
  483.                 behaved" IPX applications are running on the machine.
  484.  
  485.          0xFF - SOCKET_ALREADY_OPEN - it will be closed upon return,
  486.                 so try again.  It is not ignored because at the point
  487.                 of call the socket shouldn't have been open, and all
  488.                 discrepancies will be caught and reported!
  489.  
  490.  
  491.   0x20 - BAD_TX_TRY - an attempt to send a packet failed, due to
  492.   failure of either the network or the configuration of the receiving
  493.   machine.  Check the global IPXerrno to discern the problem.
  494.   It should be one of the following:
  495.  
  496.          0xFC - EVENT_CANCELED - send request was canceled by
  497.         application due to timeout.
  498.  
  499.          0xFD - FRAGMENT_SIZE_ERROR - malformed packet size, either
  500.                 less than 30 bytes or greater than 576 bytes, or
  501.                 the event control block's Fragment Count field was 0.
  502.  
  503.          0xFE - DESTINATION_NOT_FOUND - the destination machine,
  504.                 specified in the NETADDR parameter, is not on the
  505.                 network or not powered up.
  506.  
  507.          0xFF - NETWORK_FAILURE - network or hardware failure.
  508.  
  509.  
  510.   0x21 - BAD_RETRIES - the receiver, while awaiting data from the
  511.   sending machine, has exhausted its retry number & count series.
  512.   Check IPXerrno for:
  513.  
  514.          0xFC - EVENT_CANCELED - listen request was canceled by
  515.                 application due to timeout.
  516.  
  517.      0xFD - FRAGMENT_SIZE_ERROR - either the event control block's
  518.                 Fragment Count field was 0, or the receiver's buffer
  519.                 space was too small to hold the incoming data.
  520.  
  521.          0xFF - ECB_SOCKET_NOT_OPEN - Socket for listening has not
  522.                 been opened by the application.
  523.  
  524.  
  525.   0x22 - BAD_RX_SEQ_NUM - the receiving machine has received a block
  526.   of data whose sequence number is unexpected. If this has occured,
  527.   a network failure has caused the transmission to become garbled,
  528.   or the sending machine had aborted the current send/received sequence
  529.   and restarted anew within the retry number & timeout series of the
  530.   receiving machine.  Both scenarios are highly unlikely.
  531.  
  532.  
  533.   0x30 - BAD_FILE_OPEN - the file to be received, specified by
  534.   the FileOrBfr parameter, could not be opened.  Check syntax of
  535.   ASCIIZ string to make sure path and filename are correct, and
  536.   don't forget to use double slashes in the string when specifying
  537.   a path! For example, "D:\MYPATH\MYFILE.DAT" is not a valid C
  538.   string. You must pass it as "D:\\MYPATH\\MYFILE.DAT".
  539.  
  540.  
  541.   0x31 - BAD_FILE_WRITE - problem writing to the file specified in the
  542.   parameter FileOrBfr, even though the file was successfully opened.
  543.   This should never occur, barring disk failure or some strange
  544.   interaction between the caller's program and other programs running
  545.   as background processes or TSR's.
  546.  
  547.  
  548.   0xBB - USER_TERMINATED - the user has chosen to abort the application
  549.   by hitting the two SHIFT keys & an ALT key during a send/receive sequence.
  550.  
  551.  
  552.   0xDD - IPX_NOT_PRESENT - IPX API interface was not detected. Make
  553.   sure NOVELL's IPX.COM or equivalent has been run before attempting to
  554.   access IPX functions.
  555.  
  556.  
  557.   -------------------------
  558.   -------------------------
  559.   APPLICATION CODE EXAMPLE:
  560.   -------------------------
  561.   -------------------------
  562.  
  563.   #include "ipx.h"
  564.   #define RXSOCKET  "4050"
  565.   #define RXBFRSIZE  8192
  566.  
  567.   int main( void )
  568.   {
  569.   unsigned rc;
  570.   long     len;
  571.   BYTE     *RxBfr;
  572.  
  573.   // receiving a file
  574.   len = 0;
  575.   rc = IPXReceiveRT( &len, "RXDATA.DAT", RXSOCKET, NULL );
  576.   if ( rc != GOOD_IPX_RETURN )
  577.      {
  578.      printf( "FUNCTION ERROR: %02X  IPX ERROR: %02X", rc, IPXerrno );
  579.      // take appropriate error action here
  580.      return( -1 );
  581.      }
  582.  
  583.   // receiving a buffer
  584.   RxBfr = calloc( 1, RXBFRSIZE );
  585.   if ( !RxBfr )
  586.      {
  587.      printf( "MEMORY ALLOCATION FAILURE!" );
  588.      return( -1 );
  589.      }
  590.  
  591.   len = RXBFRSIZE;
  592.   rc = IPXReceiveRT( &len, RxBfr, RXSOCKET, NULL );
  593.   if ( rc != GOOD_IPX_RETURN )
  594.      {
  595.      printf( "FUNCTION ERROR: %02X  IPX ERROR: %02X", rc, IPXerrno );
  596.      // take appropriate error action here
  597.      return( -1 );
  598.      }
  599.  
  600.   return( 0 );
  601.   }
  602.  
  603. */
  604. /*******************************************************************/
  605. /*******************************************************************/
  606.  
  607. unsigned IPXReceiveRT( long  *BfrLen,
  608.                        BYTE  *FileOrBfr,
  609.                        char  *SocketStr,
  610.                        void  (*RTfunc)(void) )
  611. {
  612.  
  613. int             fhandle;
  614. long            totRX;
  615. BYTE            *RXptr;
  616. unsigned        rc, lenRX, retries;
  617. int             TXflg, fileflg;
  618. BYTE            Socket[2];
  619. BYTE            expected_seq;
  620. NETADDR         TXna;
  621.  
  622. BYTE               *pIPXbfrRX, *pIPXbfrTX;
  623. IPXHEADER          *pIPXpktRX, *pIPXpktTX;
  624. EVENTCONTROLBLOCK  *pIPXecbRX, *pIPXecbTX;
  625. LOCALTARGET        *pLocalTarget;
  626.  
  627. /* -------------------------------------------------------------- */
  628. /* check that IPX API has been installed or attempt to install it */
  629. /* -------------------------------------------------------------- */
  630.  
  631. if (
  632.     !(IPXAPI)
  633.       &&
  634.     (IPXInstalled() != IPX_PRESENT)
  635.    )
  636.    {
  637.    return( IPX_NOT_PRESENT );
  638.    }
  639.  
  640. /* ------------------------------------------- */
  641. /* open socket for peer-to-peer communications */
  642. /* ------------------------------------------- */
  643.  
  644. if (
  645.     (strlen( SocketStr ) != (sizeof(Socket)*2)) // 2 ASCII chars per byte
  646.       ||
  647.     !(xatoxb( Socket, SocketStr ))
  648.    )
  649.    {
  650.    return( BAD_SOCKET_PARAM );
  651.    }
  652.  
  653. IPXerrno = IPXSocketOpen( Socket, SOCKET_SHORT_LIVED );
  654. if ( IPXerrno != IPX_SUCCESS )
  655.    {
  656.    if ( IPXerrno == SOCKET_ALREADY_OPEN )
  657.       /*
  658.          sure, we could just go ahead,
  659.          but the socket really shouldn't have been open at this point,
  660.          and until this library has been thoroughly shaken out,
  661.          (hopefully) ALL discrepancies will be caught & reported!
  662.       */
  663.       {
  664.       IPXSocketClose( Socket );
  665.       }
  666.    return( BAD_SOCKET_OPEN );
  667.    }
  668.  
  669. /* -------------------- */
  670. /* set the receive mode */
  671. /* -------------------- */
  672.  
  673. fileflg = TRUE;
  674. if ( *BfrLen )
  675.    {
  676.    RXptr = FileOrBfr;
  677.    fileflg = !TRUE;
  678.    }
  679.  
  680. /* ----------------------- */
  681. /* attempt to open RX file */
  682. /* ----------------------- */
  683.  
  684. if ( fileflg )
  685.    {
  686.    fhandle = open( FileOrBfr,
  687.            O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
  688.            S_IREAD | S_IWRITE );
  689.    if ( fhandle == FILE_PROBLEM )
  690.       {
  691.       IPXSocketClose( Socket );
  692.       return( BAD_FILE_OPEN );
  693.       }
  694.    }
  695.  
  696. /* ------------------------- */
  697. /* allocate necessary memory */
  698. /* ------------------------- */
  699.  
  700. pIPXbfrRX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
  701. pIPXbfrTX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
  702. pIPXpktRX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
  703. pIPXpktTX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
  704. pIPXecbRX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
  705. pIPXecbTX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
  706. pLocalTarget = (LOCALTARGET *)calloc( 1, sizeof(LOCALTARGET) );
  707.  
  708. if (
  709.      pIPXbfrRX == NULL ||
  710.      pIPXbfrTX == NULL ||
  711.      pIPXpktRX == NULL ||
  712.      pIPXpktTX == NULL ||
  713.      pIPXecbRX == NULL ||
  714.      pIPXecbTX == NULL ||
  715.      pLocalTarget == NULL
  716.    )
  717.    {
  718.    IPXSocketClose( Socket );
  719.    *BfrLen = 0;
  720.    if ( fileflg )
  721.       {
  722.       close( fhandle );
  723.       unlink( FileOrBfr );
  724.       }
  725.    if ( pIPXbfrRX )
  726.       free( pIPXbfrRX );
  727.    if ( pIPXbfrTX )
  728.       free( pIPXbfrTX );
  729.    if ( pIPXpktRX )
  730.       free( pIPXpktRX );
  731.    if ( pIPXpktTX )
  732.       free( pIPXpktTX );
  733.    if ( pIPXecbRX )
  734.       free( pIPXecbRX );
  735.    if ( pIPXecbTX )
  736.       free( pIPXecbTX );
  737.    if ( pLocalTarget )
  738.       free( pLocalTarget );
  739.    return( BAD_MEMORY_ALLOC );
  740.    }
  741.  
  742. /* --------------------------- */
  743. /* initialize ECBs/IPX packets */
  744. /* --------------------------- */
  745.  
  746. memcpy( pIPXecbRX->Socket, Socket, sizeof(pIPXecbRX->Socket) );
  747. pIPXpktRX->PacketType          = IPX_PACKET_TYPE;
  748. pIPXecbRX->FragmentCnt         = 2;
  749. pIPXecbRX->Fragment[0].BufAddr = (void *)pIPXpktRX;
  750. pIPXecbRX->Fragment[0].Len     = sizeof(IPXHEADER);
  751. pIPXecbRX->Fragment[1].BufAddr = (void *)pIPXbfrRX;
  752. pIPXecbRX->Fragment[1].Len     = SEQLEN+IPXdatalen;
  753.  
  754. memcpy( pIPXecbTX->Socket, Socket, sizeof(pIPXecbTX->Socket) );
  755. pIPXpktTX->PacketType          = IPX_PACKET_TYPE;
  756. pIPXecbTX->FragmentCnt         = 2;
  757. pIPXecbTX->Fragment[0].BufAddr = (void *)pIPXpktTX;
  758. pIPXecbTX->Fragment[0].Len     = sizeof(IPXHEADER);
  759. pIPXecbTX->Fragment[1].BufAddr = (void *)pIPXbfrTX;
  760. pIPXecbTX->Fragment[1].Len     = SEQLEN+strlen( ACKSTR );
  761. strcpy( pIPXbfrTX+SEQLEN, ACKSTR );
  762.  
  763. /* =================== */
  764. /* DATA RX/ACK TX LOOP */
  765. /* =================== */
  766.  
  767. expected_seq = FIRST_SEQ_NUM;
  768. TXflg = !TRUE;
  769. retries = 0;
  770. totRX = 0;
  771. while ( TRUE )
  772.   {
  773.  
  774.   /* if user decides to break it off, then quit */
  775.   if ( USERBREAK )
  776.      {
  777.      rc = USER_TERMINATED;
  778.      break;
  779.      }
  780.  
  781.   /* issue LISTEN for pending RX of data */
  782.   IPXListenForPacket( pIPXecbRX );
  783.  
  784.   /* ----------------------------- */
  785.   /* issue SEND to ACK previous RX */
  786.   /* ----------------------------- */
  787.  
  788.   if ( TXflg )
  789.      {
  790.  
  791.      /* RX source address = TX destination address */
  792.      memcpy( &pIPXpktTX->DestAddr, &TXna, sizeof(NETADDR) );
  793.  
  794.      /* must also fill immediate address of ECB */
  795.      memcpy( pLocalTarget, &TXna, sizeof(NETADDR) );
  796.  
  797.      IPXerrno = IPXGetLocalTarget( pLocalTarget );
  798.      if ( IPXerrno != IPX_SUCCESS )
  799.         {
  800.         IPXCancelEvent( pIPXecbRX );
  801.         rc = BAD_LOCAL_TARGET;
  802.         break;
  803.         }
  804.  
  805.      memcpy( pIPXecbTX->ImmediateAddr,
  806.              pLocalTarget->ImmediateAddr,
  807.              sizeof(pIPXecbTX->ImmediateAddr) );
  808.  
  809.      /* retain RX seq # for ACK */
  810.      *pIPXbfrTX = *pIPXbfrRX;
  811.  
  812.      /* send the ACK & check result of TX */
  813.      IPXSendPacket( pIPXecbTX );
  814.      IPXTimeOutRT( pIPXecbTX, IPXto, RTfunc );
  815.      IPXerrno = pIPXecbTX->CompletionCode;
  816.      if ( IPXerrno != IPX_SUCCESS )
  817.     {
  818.     IPXCancelEvent( pIPXecbRX );
  819.     rc = BAD_TX_TRY;
  820.     break;
  821.     }
  822.  
  823.      /* ------------------------ */
  824.      /* TX was successfully sent */
  825.      /* ------------------------ */
  826.  
  827.      /* if the previous RX data that we are now ACKing */
  828.      /* did not fill the RX buffer, consider it EOT    */
  829.      if ( lenRX < IPXdatalen )
  830.     {
  831.     IPXCancelEvent( pIPXecbRX );
  832.     rc = GOOD_IPX_RETURN;
  833.     break;
  834.     }
  835.  
  836.      } // end of if ( TXflg )
  837.  
  838.   /* -------------- */
  839.   /* monitor LISTEN */
  840.   /* -------------- */
  841.  
  842.   /* monitor result of pending LISTEN */
  843.   IPXTimeOutRT( pIPXecbRX, IPXto, RTfunc );
  844.   IPXerrno = pIPXecbRX->CompletionCode;
  845.  
  846.   /* ----------------- */
  847.   /* RX was successful */
  848.   /* ----------------- */
  849.  
  850.   if ( IPXerrno == IPX_SUCCESS )
  851.      {
  852.  
  853.      /* if first RX then save Sender's address */
  854.      if ( !totRX )
  855.     {
  856.     memcpy( &TXna, &pIPXpktRX->SrceAddr, sizeof(NETADDR) );
  857.     }
  858.  
  859.      /* ignore all but latest Sender */
  860.      if ( memcmp( &TXna, &pIPXpktRX->SrceAddr, sizeof(NETADDR) ) )
  861.     {
  862.     TXflg = !TRUE;
  863.     continue;
  864.     }
  865.  
  866.      /* check sequence number */
  867.      if ( expected_seq != *pIPXbfrRX )
  868.     {
  869.     rc = BAD_RX_SEQ_NUM;
  870.     break;
  871.     }
  872.  
  873.      /* if any data was received, then save it */
  874.      lenRX = HILOSWAP( pIPXpktRX->Len ) - (sizeof(IPXHEADER)+SEQLEN);
  875.      if ( lenRX )
  876.     {
  877.  
  878.     /* data to be written to file */
  879.     if ( fileflg )
  880.        {
  881.        rc = write( fhandle, pIPXbfrRX+SEQLEN, lenRX );
  882.        if ( lenRX != rc )
  883.           {
  884.           rc = BAD_FILE_WRITE;
  885.           break;
  886.           }
  887.        }
  888.  
  889.     /* data to be copied into buffer */
  890.     if ( !fileflg )
  891.        {
  892.        totRX += lenRX;
  893.        if ( *BfrLen < totRX )
  894.           {
  895.           rc = BAD_RX_BFR_LEN;
  896.           break;
  897.           }
  898.        memcpy( RXptr, pIPXbfrRX+SEQLEN, lenRX );
  899.        RXptr += lenRX;
  900.        }
  901.  
  902.     } // end of if ( lenRX )
  903.  
  904.      /* ACK is now owed to sender; clear retry cnts & bump seq # */
  905.      TXflg = TRUE;
  906.      retries = 0;
  907.      expected_seq++;
  908.  
  909.      } // end of if ( IPXerrno == IPX_SUCCESS )
  910.  
  911.   /* --------------------- */
  912.   /* RX was NOT successful */
  913.   /* --------------------- */
  914.  
  915.   if ( IPXerrno != IPX_SUCCESS )
  916.      {
  917.  
  918.      /* if maximum retries have been exhausted, then quit */
  919.      if ( retries++ >= IPXtries )
  920.     {
  921.     rc = BAD_RETRIES;
  922.     break;
  923.     }
  924.  
  925.      } // end of if ( IPXerrno != IPX_SUCCESS )
  926.  
  927.   } // end of while ( TRUE )
  928.  
  929. /* ---------------- */
  930. /* bring it on home */
  931. /* ---------------- */
  932.  
  933. IPXSocketClose( Socket );
  934.  
  935. /* if file mode, close it & delete it if something went wrong */
  936. if ( fileflg )
  937.    {
  938.    close( fhandle );
  939.    if ( rc != GOOD_IPX_RETURN )
  940.       {
  941.       unlink( FileOrBfr );
  942.       }
  943.    }
  944.  
  945. /* if buffer mode, set number of bytes read into buffer */
  946. if ( !fileflg )
  947.    {
  948.    *BfrLen = totRX;
  949.    if ( rc != GOOD_IPX_RETURN )
  950.       {
  951.       *BfrLen = 0;
  952.       }
  953.    }
  954.  
  955. /* free that mem! */
  956. free( pIPXbfrRX );
  957. free( pIPXbfrTX );
  958. free( pIPXpktRX );
  959. free( pIPXpktTX );
  960. free( pIPXecbRX );
  961. free( pIPXecbTX );
  962. free( pLocalTarget );
  963.  
  964. return( rc );
  965. }
  966.  
  967. /*******************************************************************/
  968. /*******************************************************************/
  969. /*
  970.   ---------------------
  971.   ---------------------
  972.   FUNCTION: IPXSendRT()
  973.   ---------------------
  974.   ---------------------
  975.  
  976.   Send a file or buffer to specified destination machine
  977.  
  978.   ----------
  979.   ----------
  980.   PROTOTYPE:
  981.   ----------
  982.   ----------
  983.  
  984.   unsigned IPXSendRT( long     *BfrLen,
  985.                       BYTE     *FileOrBfr,
  986.                       char     *SocketStr,
  987.                       NETADDR  *Destination,
  988.                       void     (*RTfunc)(void) );
  989.  
  990.   ---------
  991.   ---------
  992.   INPUT(S):
  993.   ---------
  994.   ---------
  995.  
  996.   BfrLen = 0 if sending a file
  997.              OR
  998.            the # of bytes to send from a given byte buffer
  999.  
  1000.   FileOrBfr = (string) name of file (path optional) to send
  1001.                 OR
  1002.               pointer to given byte buffer from which to send data
  1003.  
  1004.   SocketStr = 4 character hex-ASCII string of IPX Socket to
  1005.               use for sending. Note that certain NOVELL sockets
  1006.               are reserved, and the caller is cautioned to use
  1007.               socket numbers "40xx", e.g., "4010", "40A1", etc.
  1008.  
  1009.   Destination = structure containing Network Address, Node
  1010.                 Address, and receiving socket number of the
  1011.                 machine that is to receive the file/buffer data.
  1012.                 See IPX.H for structure layout; if needed, use
  1013.                 function xatoxb() for converting hex-ascii
  1014.                 strings to hex-binary bytes.
  1015.  
  1016.   RTfunc    = pointer to a function which is to be called during
  1017.               time out loops when IPX command is pending.  Set
  1018.               to NULL if you don't need this "real time" capability.
  1019.  
  1020.   ----------
  1021.   ----------
  1022.   RETURN(S):
  1023.   ----------
  1024.   ----------
  1025.  
  1026.   0x00 - GOOD_IPX_RETURN - all went well.
  1027.  
  1028.  
  1029.   0x10 - BAD_LOCAL_TARGET - the internal IPX call to find the receiver's
  1030.   local target failed.  Check the global variable IPXerrno for the
  1031.   specific reason, e.g.:
  1032.  
  1033.          0xFA - DEST_NODE_PATH_NOT_FND - the 6-byte node address
  1034.                 specified in the passed parameter Destination.INA.Node
  1035.                 could not be found.  Either the node is non-extant, or
  1036.                 the machine with that node is not powered on.
  1037.  
  1038.  
  1039.   0x11 - BAD_SOCKET_PARAM - the SocketStr parameter did not consist of
  1040.   a string of four hex-ascii digits.
  1041.  
  1042.  
  1043.   0x12 - BAD_SOCKET_OPEN - the attempt to open the socket specified in
  1044.   SocketStr parameter failed.  The global variable IPXerrno will contain
  1045.   return code received from IPX.  It can be one of the following:
  1046.  
  1047.          0xFE - SOCKET_TABLE_FULL - each machine gets 20 sockets, so
  1048.                 this error should never occur unless other non-"well
  1049.                 behaved" IPX applications are running on the machine.
  1050.  
  1051.          0xFF - SOCKET_ALREADY_OPEN - it will be closed upon return,
  1052.                 so try again.  It is not ignored because at the point
  1053.                 of call the socket shouldn't have been open, and all
  1054.                 discrepancies will be caught and reported!
  1055.  
  1056.  
  1057.   0x20 - BAD_TX_TRY -  the attempt to send an IPX packet failed due to
  1058.   a problem of either the network or the configuration of the sending
  1059.   machine. Check the global IPXerrno to discern the problem.  It should
  1060.   be one of the following:
  1061.  
  1062.          0xFC - EVENT_CANCELED - send request was canceled by
  1063.                 application due to timeout.
  1064.  
  1065.          0xFD - FRAGMENT_SIZE_ERROR - malformed packet size, either
  1066.                 less than 30 bytes or greater than 576 bytes, or
  1067.                 the event control block's Fragment Count field was 0.
  1068.  
  1069.          0xFE - DESTINATION_NOT_FOUND - the destination machine,
  1070.                 specified in the NETADDR parameter, is not on the
  1071.                 network or not powered up.
  1072.  
  1073.          0xFF - NETWORK_FAILURE - network or hardware failure.
  1074.  
  1075.  
  1076.   0x21 - BAD_RETRIES - the sender has been awaiting an acknowledgement
  1077.   from the receiver for most recently sent data, and has exhausted its
  1078.   retry number & count series.  Check IPXerrno for:
  1079.  
  1080.          0xFC - EVENT_CANCELED - listen request was canceled by
  1081.                 application due to timeout.
  1082.  
  1083.          0xFD - FRAGMENT_SIZE_ERROR - either the event control block's
  1084.                 Fragment Count field was 0, or the receiver's buffer
  1085.                 space was too small to hold the incoming data.
  1086.  
  1087.          0xFF - ECB_SOCKET_NOT_OPEN - Socket for listening has not
  1088.                 been opened by the application.
  1089.  
  1090.  
  1091.   0x22 - BAD_RX_SEQ_NUM - the destination machine has transmitted an
  1092.   acknowledgement to received data, but the sequence number does not
  1093.   match the sequence number of the data that the sender transmitted.
  1094.   If this problem occurs, either a network failure has caused the
  1095.   transmission to become garbled, or the destination machine had
  1096.   aborted the current send/received sequence and restarted anew
  1097.   within the retry number & timeout series of the sender.
  1098.   Both scenarios are highly unlikely.
  1099.  
  1100.   0x23 - BAD_RX_SRCE_ADDR - the sending machine received a transmission
  1101.   from a machine other than the expected receiver of the original trans-
  1102.   mission.  This should never occur, due to the fact that the sender
  1103.   socket should be known at this point only to the receiver of the
  1104.   message that the sender transmitted.  If other machines transmitting
  1105.   on the network are getting through to another sender unexpectedly, then
  1106.   some application software debugging is in order, or special TSR programs
  1107.   are running, the behavior of which should be monitored more stringently.
  1108.  
  1109.  
  1110.   0x30 - BAD_FILE_OPEN - the file to be transmitted, specified by
  1111.   the FileOrBfr parameter, could not be opened.  Check syntax of
  1112.   ASCIIZ string to make sure path and filename are correct, and
  1113.   don't forget to use double slashes in the string when specifying
  1114.   a path! For example, "D:\MYPATH\MYFILE.DAT" is not a valid C
  1115.   string. You must pass it as "D:\\MYPATH\\MYFILE.DAT".
  1116.  
  1117.  
  1118.   0x32 - BAD_FILE_READ - problem reading the file specified in the
  1119.   parameter FileOrBfr, even though the file was successfully opened.
  1120.   This should never occur, barring disk failure or some strange
  1121.   interaction between the caller's program and other programs running
  1122.   as background processes or TSR's.
  1123.  
  1124.  
  1125.   0xBB - USER_TERMINATED - the user has chosen to abort the application
  1126.   by hitting the two SHIFT keys & an ALT key during a send/receive sequence.
  1127.  
  1128.  
  1129.   0xDD - IPX_NOT_PRESENT - IPX API interface was not detected. Make
  1130.   sure NOVELL's IPX.COM or equivalent has been run before attempting to
  1131.   access IPX functions.
  1132.  
  1133.  
  1134.   -------------------------
  1135.   -------------------------
  1136.   APPLICATION CODE EXAMPLE:
  1137.   -------------------------
  1138.   -------------------------
  1139.  
  1140.   #define TXSOCKET  "4050"
  1141.   #define TXBFRSIZE  8192
  1142.  
  1143.   int main( void )
  1144.   {
  1145.   NETADDR  na;
  1146.   unsigned rc;
  1147.   long     len;
  1148.   BYTE     *TxBfr;
  1149.  
  1150.   // hard-coded example of internetwork address of destination machine
  1151.   xatoxb( na.INA.Network, "01234567" );
  1152.   xatoxb( na.INA.Node, "0123456789AB" );
  1153.   xatoxb( na.Socket, "4010" );
  1154.  
  1155.   // sending a file
  1156.   len = 0;
  1157.   rc = IPXSendRT( &len, "TXDATA.DAT", TXSOCKET, &na, NULL );
  1158.   if ( rc != GOOD_IPX_RETURN )
  1159.      {
  1160.      // take appropriate error action here
  1161.      return( -1 );
  1162.      }
  1163.  
  1164.   // sending a buffer
  1165.   TxBfr = calloc( 1, TXBFRSIZE );
  1166.   if ( !TxBfr )
  1167.      {
  1168.      printf( "MEMORY ALLOCATION FAILURE!" );
  1169.      return( -1 );
  1170.      }
  1171.  
  1172.   len = TXBFRSIZE;
  1173.   rc = IPXSendRT( &len, TxBfr, TXSOCKET, &na, NULL );
  1174.   if ( rc != GOOD_IPX_RETURN )
  1175.      {
  1176.      printf( "FUNCTION ERROR: %02X  IPX ERROR: %02X", rc, IPXerrno );
  1177.      // take appropriate error action here
  1178.      return( -1 );
  1179.      }
  1180.  
  1181.   return( 0 );
  1182.   }
  1183.  
  1184. */
  1185. /*******************************************************************/
  1186. /*******************************************************************/
  1187.  
  1188. unsigned IPXSendRT( long     *BfrLen,
  1189.                     BYTE     *FileOrBfr,
  1190.                     char     *SocketStr,
  1191.                     NETADDR  *Destination,
  1192.                     void     (*RTfunc)(void) )
  1193. {
  1194. int       fhandle;
  1195. unsigned  rc, lenTX, retries;
  1196. BYTE      *TXptr;
  1197. int       retryTXflg, fileflg;
  1198. BYTE      Socket[2];
  1199. BYTE      expected_seq;
  1200.  
  1201. BYTE               *pIPXbfrRX, *pIPXbfrTX;
  1202. IPXHEADER          *pIPXpktRX, *pIPXpktTX;
  1203. EVENTCONTROLBLOCK  *pIPXecbRX, *pIPXecbTX;
  1204. LOCALTARGET        *pLocalTarget;
  1205.  
  1206. /* ----------------------------------------------------------- */
  1207. /* check that IPX API has been installed or attempt to install */
  1208. /* ----------------------------------------------------------- */
  1209.  
  1210. if (
  1211.     !(IPXAPI)
  1212.       &&
  1213.     (IPXInstalled() != IPX_PRESENT)
  1214.    )
  1215.    {
  1216.    return( IPX_NOT_PRESENT );
  1217.    }
  1218.  
  1219. /* ------------------------------------------- */
  1220. /* open socket for peer-to-peer communications */
  1221. /* ------------------------------------------- */
  1222.  
  1223. if (
  1224.     (strlen( SocketStr ) != (sizeof(Socket)*2))
  1225.       ||
  1226.     !(xatoxb( Socket, SocketStr ))
  1227.    )
  1228.    {
  1229.    return( BAD_SOCKET_PARAM );
  1230.    }
  1231.  
  1232. IPXerrno = IPXSocketOpen( Socket, SOCKET_SHORT_LIVED );
  1233. if ( IPXerrno != IPX_SUCCESS )
  1234.    {
  1235.    if ( IPXerrno == SOCKET_ALREADY_OPEN )
  1236.       {
  1237.       IPXSocketClose( Socket );
  1238.       }
  1239.    return( BAD_SOCKET_OPEN );
  1240.    }
  1241.  
  1242. /* --------------------- */
  1243. /* set the transfer mode */
  1244. /* --------------------- */
  1245.  
  1246. fileflg = TRUE;
  1247. if ( *BfrLen )
  1248.    {
  1249.    TXptr = FileOrBfr;
  1250.    fileflg = !TRUE;
  1251.    }
  1252.  
  1253. /* ------------------------------- */
  1254. /* check that TX file is available */
  1255. /* ------------------------------- */
  1256.  
  1257. if ( fileflg )
  1258.    {
  1259.    fhandle = open( FileOrBfr, O_RDONLY | O_BINARY );
  1260.    if ( fhandle == FILE_PROBLEM )
  1261.       {
  1262.       IPXSocketClose( Socket );
  1263.       return( BAD_FILE_OPEN );
  1264.       }
  1265.    }
  1266.  
  1267. /* ------------------------- */
  1268. /* allocate necessary memory */
  1269. /* ------------------------- */
  1270.  
  1271. pIPXbfrRX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
  1272. pIPXbfrTX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
  1273. pIPXpktRX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
  1274. pIPXpktTX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
  1275. pIPXecbRX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
  1276. pIPXecbTX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
  1277. pLocalTarget = (LOCALTARGET *)calloc( 1, sizeof(LOCALTARGET) );
  1278.  
  1279. if (
  1280.      pIPXbfrRX == NULL ||
  1281.      pIPXbfrTX == NULL ||
  1282.      pIPXpktRX == NULL ||
  1283.      pIPXpktTX == NULL ||
  1284.      pIPXecbRX == NULL ||
  1285.      pIPXecbTX == NULL ||
  1286.      pLocalTarget == NULL
  1287.    )
  1288.    {
  1289.    IPXSocketClose( Socket );
  1290.    if ( fileflg )
  1291.       close( fhandle );
  1292.    if ( pIPXbfrRX )
  1293.       free( pIPXbfrRX );
  1294.    if ( pIPXbfrTX )
  1295.       free( pIPXbfrTX );
  1296.    if ( pIPXpktRX )
  1297.       free( pIPXpktRX );
  1298.    if ( pIPXpktTX )
  1299.       free( pIPXpktTX );
  1300.    if ( pIPXecbRX )
  1301.       free( pIPXecbRX );
  1302.    if ( pIPXecbTX )
  1303.       free( pIPXecbTX );
  1304.    if ( pLocalTarget )
  1305.       free( pLocalTarget );
  1306.    return( BAD_MEMORY_ALLOC );
  1307.    }
  1308.  
  1309. /* --------------------------- */
  1310. /* initialize ECBs/IPX packets */
  1311. /* --------------------------- */
  1312.  
  1313. memcpy( pIPXecbRX->Socket, Socket, sizeof(pIPXecbRX->Socket) );
  1314. pIPXpktRX->PacketType          = IPX_PACKET_TYPE;
  1315. pIPXecbRX->FragmentCnt         = 2;
  1316. pIPXecbRX->Fragment[0].BufAddr = (void *)pIPXpktRX;
  1317. pIPXecbRX->Fragment[0].Len     = sizeof(IPXHEADER);
  1318. pIPXecbRX->Fragment[1].BufAddr = (void *)pIPXbfrRX;
  1319. pIPXecbRX->Fragment[1].Len     = SEQLEN+IPXdatalen;
  1320.  
  1321. memcpy( pIPXecbTX->Socket, Socket, sizeof(pIPXecbTX->Socket) );
  1322. pIPXpktTX->PacketType          = IPX_PACKET_TYPE;
  1323. pIPXecbTX->FragmentCnt         = 2;
  1324. pIPXecbTX->Fragment[0].BufAddr = (void *)pIPXpktTX;
  1325. pIPXecbTX->Fragment[0].Len     = sizeof(IPXHEADER);
  1326. pIPXecbTX->Fragment[1].BufAddr = (void *)pIPXbfrTX;
  1327.  
  1328. memcpy( &pIPXpktTX->DestAddr, Destination, sizeof(NETADDR) );
  1329. memcpy( pLocalTarget, Destination, sizeof(INTNETADDR) );
  1330. IPXerrno = IPXGetLocalTarget( pLocalTarget );
  1331. if ( IPXerrno != IPX_SUCCESS )
  1332.    {
  1333.    IPXSocketClose( Socket );
  1334.    if ( fileflg )
  1335.       close( fhandle );
  1336.    free( pIPXbfrRX );
  1337.    free( pIPXbfrTX );
  1338.    free( pIPXpktRX );
  1339.    free( pIPXpktTX );
  1340.    free( pIPXecbRX );
  1341.    free( pIPXecbTX );
  1342.    free( pLocalTarget );
  1343.    return( BAD_LOCAL_TARGET );
  1344.    }
  1345.  
  1346. memcpy( pIPXecbTX->ImmediateAddr,
  1347.         pLocalTarget->ImmediateAddr,
  1348.         sizeof(pIPXecbTX->ImmediateAddr) );
  1349.  
  1350. /* =================== */
  1351. /* DATA TX/ACK RX LOOP */
  1352. /* =================== */
  1353.  
  1354. expected_seq = FIRST_SEQ_NUM;
  1355. retryTXflg = !TRUE;
  1356. retries = 0;
  1357. while( TRUE )
  1358.   {
  1359.  
  1360.   /* if user chose to break things off, then quit */
  1361.   if ( USERBREAK )
  1362.      {
  1363.      rc = USER_TERMINATED;
  1364.      break;
  1365.      }
  1366.  
  1367.   /* get ready for expected ACK of imminent TX */
  1368.   IPXListenForPacket( pIPXecbRX );
  1369.  
  1370.   /* if TX retry is not active, prepare TX buffer */
  1371.   if ( !retryTXflg )
  1372.      {
  1373.  
  1374.      /* fill TX buffer with data from file */
  1375.      if ( fileflg )
  1376.         {
  1377.         lenTX = read( fhandle, pIPXbfrTX+SEQLEN, IPXdatalen );
  1378.         if ( lenTX == (unsigned)FILE_PROBLEM )
  1379.            {
  1380.            IPXCancelEvent( pIPXecbRX );
  1381.            rc = BAD_FILE_READ;
  1382.            break;
  1383.            }
  1384.         }
  1385.  
  1386.      /* fill TX buffer with data from buffer */
  1387.      if ( !fileflg )
  1388.         {
  1389.         lenTX = ((*BfrLen < IPXdatalen) ? *BfrLen : IPXdatalen);
  1390.         memcpy( pIPXbfrTX+SEQLEN, TXptr, lenTX );
  1391.         TXptr += lenTX;
  1392.         *BfrLen -= IPXdatalen;
  1393.         }
  1394.  
  1395.      /* set sequence number & buffer length */
  1396.      *pIPXbfrTX = expected_seq;
  1397.      pIPXecbTX->Fragment[1].Len = SEQLEN+lenTX;
  1398.  
  1399.      } // end of if ( !retryTXflg )
  1400.  
  1401.   /* send the data & check result of TX */
  1402.   IPXSendPacket( pIPXecbTX );
  1403.   IPXTimeOutRT( pIPXecbTX, IPXto, RTfunc );
  1404.   IPXerrno = pIPXecbTX->CompletionCode;
  1405.   if ( IPXerrno != IPX_SUCCESS )
  1406.      {
  1407.      /* cancel the pending LISTEN */
  1408.      IPXCancelEvent( pIPXecbRX );
  1409.      rc = BAD_TX_TRY;
  1410.      break;
  1411.      }
  1412.  
  1413.   /* ---------------------------------- */
  1414.   /* RX (ACK to previous TX) is pending */
  1415.   /* ---------------------------------- */
  1416.  
  1417.   /* wait for RX to complete, then check result */
  1418.   IPXTimeOutRT( pIPXecbRX, IPXto, RTfunc );
  1419.   IPXerrno = pIPXecbRX->CompletionCode;
  1420.  
  1421.   /* ----------------------------- */
  1422.   /* ACK was received successfully */
  1423.   /* ----------------------------- */
  1424.  
  1425.   if ( IPXerrno == IPX_SUCCESS )
  1426.      {
  1427.      /* check that RX was from expected Destination */
  1428.      if ( memcmp( Destination, &pIPXpktRX->SrceAddr, sizeof(NETADDR) ) )
  1429.         {
  1430.         rc = BAD_RX_SRCE_ADDR;
  1431.         break;
  1432.         }
  1433.  
  1434.      /* check that TX/RX sequence in sync */
  1435.      if ( expected_seq != *pIPXbfrRX )
  1436.         {
  1437.         rc = BAD_RX_SEQ_NUM;
  1438.         break;
  1439.         }
  1440.  
  1441.      /* if last TX was EOT, then all done! */
  1442.      if ( lenTX < IPXdatalen )
  1443.         {
  1444.         rc = GOOD_IPX_RETURN;
  1445.         break;
  1446.         }
  1447.  
  1448.     /* otherwise, do next TX */
  1449.     expected_seq++;
  1450.     retries = 0;
  1451.     retryTXflg = !TRUE;
  1452.  
  1453.     } // end of if ( IPXerrno == IPX_SUCCESS )
  1454.  
  1455.   /* ------------------- */
  1456.   /* no ACK was received */
  1457.   /* ------------------- */
  1458.  
  1459.   if ( IPXerrno != IPX_SUCCESS )
  1460.      {
  1461.  
  1462.      /* if maximum retries have been exhausted, then quit */
  1463.      if ( retries++ >= IPXtries )
  1464.         {
  1465.         rc = BAD_RETRIES;
  1466.         break;
  1467.         }
  1468.  
  1469.      /* otherwise, try RX again */
  1470.      retryTXflg = TRUE;
  1471.  
  1472.      } // end of if ( IPXerrno != IPX_SUCCESS )
  1473.  
  1474.  
  1475.   } // end of while ( TRUE )
  1476.  
  1477. /* --------------------------------- */
  1478. /* close socket and bring it on home */
  1479. /* --------------------------------- */
  1480.  
  1481. IPXSocketClose( Socket );
  1482.  
  1483. if ( fileflg )
  1484.    close( fhandle );
  1485.  
  1486. free( pIPXbfrRX );
  1487. free( pIPXbfrTX );
  1488. free( pIPXpktRX );
  1489. free( pIPXpktTX );
  1490. free( pIPXecbRX );
  1491. free( pIPXecbTX );
  1492. free( pLocalTarget );
  1493.  
  1494. return( rc );
  1495. }
  1496.  
  1497. /************************************************************************/
  1498. /* EOF  EOF  EOF  EOF  EOF  EOF  EOF  EOF  EOF  EOF  EOF  EOF  EOF  EOF */
  1499. /************************************************************************/
  1500.